<?php
/**
 * RedCross Application
 *
 * @copyright Copyright (c) 2010, Kristian Stokke Tryggestad, Rune Vikestad, Andreas Flaten Wist, Simen Nicolai Echholt, Ole Henrik Jahren
 */

/**
 * Service class for authenticating users
 *
 * @category    RedCross
 * @package     Core_Service
 */
class Core_Service_Auth implements RedCross_Service_ServiceInterface
{
    /**
     * Zend_Auth instance
     * @var Zend_Auth
     */
    private $_auth = null;

    /**
     * Zend_Auth_Adapter instance
     * @var Zend_Auth_Adapter_Interface
     */
    private $_adapter = null;

    /**
     * The table name where user information is stored
     * @var string
     */
    private $_tableName = null;

    /**
     * Column name where identity information lies
     * @var string
     */
    private $_identityColumn = null;

    /**
     * Column name where credential information lies
     * @var string
     */
    private $_credentialColumn = null;

    /**
     * Array of cached forms
     * @var array
     */
    private $_forms = array();

    /**
     * Constructor
     * Assigns the given arguments to variables
     *
     * @param Zend_Auth $auth
     * @param Zend_Auth_Adapter_Interface $adapter
     */
    public function __construct(Zend_Auth $auth, Zend_Auth_Adapter_Interface $adapter)
    {
        $this->_auth = $auth;
        $this->_adapter = $adapter;

        $this->_tableName = 'Core_Model_User';
        $this->_identityColumn = 'username';
    }

    public function getValidator()
    {
        return $this->getLoginForm();
    }

    /**
     * Attempts to authenticate a user
     * @param array $data Array consisting of username and password keys
     */
    public function login(array $data)
    {
        if (!$this->getValidator()->isValid($data)) {
        	throw new RedCross_Exception_ValidationFailed();
        }

        $username = $this->getValidator()->getValue('username');
        $password = $this->getValidator()->getValue('password');

        $result = $this->authenticate($username, $password);
        if (!$result->isValid()) {
        	switch ($result->getCode()) {
        	    case Zend_Auth_Result::FAILURE_UNCATEGORIZED:
        	        // The user is not yet confirmed by the administrator
        	        $this->getLoginForm()->setDescription('Denne brukeren har ikke blitt aktivert eller har blitt merket som inaktiv av administrator');
        	        break;
        	    default:
        	        // Default error.. Could be wrong username, password, etc.
        	        $this->getLoginForm()->setDescription('Brukernavn eller passord var feil');
        	        break;
        	}
        	return false;
        }

        $filter = new Zend_Filter_Boolean(array(
			'type' => array(
                Zend_Filter_Boolean::INTEGER,
                Zend_Filter_Boolean::ZERO,
            ),
        ));
        $rememberMe = $filter->filter($this->getLoginForm()->getValue('rememberMe'));
        if ($rememberMe) {
            $cookie = Core_Model_User::createSalt();
            $this->setCookie($cookie);
        }
        return true;
             
    }

    /**
     * Authenticates a user based on the given arguments
     *
     * @param string $username
     * @param string $password
     * @return Zend_Auth_Result
     */
    public function authenticate($username, $password, $cookie = false)
    {
        if ($cookie)
            $this->_credentialColumn = 'cookie';
        else
            $this->_credentialColumn = 'password';
        $this->_setupAuthAdapter($username, $password, $cookie);

        $result = $this->_auth->authenticate($this->_adapter);
        if ($result->isValid()) {
            $identity = $this->_adapter->getResultRowObject(null, array('password', 'salt', 'cookie'));
            $this->_auth->getStorage()->write($identity);

            /**
             * TODO: update user last login date and IP
             */
        }
        return $result;
    }

    /**
     * Configures the authentication adapter
     *
     * @param string $username
     * @param string $password
     */
    private function _setupAuthAdapter($username, $password, $cookie)
    {
        // TODO:
        // The credentialTreatment directive implemented in Zend 1.11 would
        // allow for checking whether a member is currently active in this 
        // method as opposed to RedCross_Auth_Doctrine_Adapter where it 
        // currently lives (I know, I know...).

        if (null !== $this->_tableName) {
        	$this->_adapter->setTableName($this->_tableName);
        }

        if (null !== $this->_identityColumn) {
            $this->_adapter->setIdentityColumn($this->_identityColumn);
        }

        if (null !== $this->_credentialColumn) {
            $this->_adapter->setCredentialColumn($this->_credentialColumn);
        } 
        $this->_adapter->setIdentity($username)->setCredential($password, $cookie);
    }
    
    	private function setCookie($cookie = null)
	{
	    $userId = $this->_auth->getIdentity()->id;

		$q = Doctrine_Query::create()
                    ->update('Core_Model_User');
		    
		if ($cookie === null) {
		    $q->set('cookie', 'NULL');
            // TODO: Replace hard-coded cookie-path with one obtained from 
            // Zend_Registry
		    //$config = Zend_Registry::get('config');
		    setcookie('rememberme', '', time()-3600*24, '/');
		    //setcookie('rememberme', '', time()-3600*24, $config['cookies']['path']);
		    	//, $config['cookies']['domain'], false, true);
		} else {
            $q->set('cookie', '?', $cookie);
		   // $config = Zend_Registry::get('config');
		    $username = $this->_auth->getIdentity()->username;
		    setcookie('rememberme', $username . ':' . $cookie, time()+60*60*24*60, '/');
		    //setcookie('rememberme', $username . ':' . $cookie, time()+60*60*24*60, $config['cookies']['path']);
		    //, $config['cookies']['domain'], false, true);
		}
                $q->where('id = ?', $userId);
		return $q->execute();               
	}

    /**
     * Clears the identity of the user and therefore
     * deauthenticates the user
     */
    public function logout()
    {
	$this->setCookie();
        $this->_auth->clearIdentity();
    }

    /**
     * Returns true if an identity is available
     *
     * @return bool is the user authenticated?
     */
    public function isAuthenticated()
    {
        return $this->_auth->hasIdentity();
    }

    /**
     * Returns the identity or null if no identity is available
     *
     * @return stdClass|null
     */
    public function getIdentity()
    {
        return $this->_auth->getIdentity();
    }

    /**
     * Retrieves an instance of the form used for authenticating the user
     *
     * @return Core_Form_User_Login
     */
    public function getLoginForm()
    {
        if (!isset($this->_forms['login'])) {
            $this->_forms['login'] = new Core_Form_User_Login();
        }
        return $this->_forms['login'];
    }

}
